namespace IgorPavlov.SevenZip.Core.Compression.LZMA.dec
{
    sealed class LenDecoder
    {
        private RangeCoder.BitDecoder 
            m_Choice,
            m_Choice2;

        private readonly RangeCoder.BitTreeDecoder[] 
            m_LowCoder = new RangeCoder.BitTreeDecoder[Base.kNumPosStatesMax],
            m_MidCoder = new RangeCoder.BitTreeDecoder[Base.kNumPosStatesMax];

        private readonly RangeCoder.BitTreeDecoder m_HighCoder = new RangeCoder.BitTreeDecoder(Base.kNumHighLenBits);
        
        uint m_NumPosStates;

        public void Create(uint numPosStates)
        {
            for (uint posState = m_NumPosStates; posState < numPosStates; posState++)
            {
                m_LowCoder[posState] = new RangeCoder.BitTreeDecoder(Base.kNumLowLenBits);
                m_MidCoder[posState] = new RangeCoder.BitTreeDecoder(Base.kNumMidLenBits);
            }
            m_NumPosStates = numPosStates;
        }

        public void Init()
        {
            m_Choice.Init();
            for (uint posState = 0; posState < m_NumPosStates; posState++)
            {
                m_LowCoder[posState].Init();
                m_MidCoder[posState].Init();
            }
            m_Choice2.Init();
            m_HighCoder.Init();
        }

        public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState)
        {
            if (m_Choice.Decode(rangeDecoder) == 0)
                return m_LowCoder[posState].Decode(rangeDecoder);
            
            uint symbol = Base.kNumLowLenSymbols;
            if (m_Choice2.Decode(rangeDecoder) == 0)
                symbol += m_MidCoder[posState].Decode(rangeDecoder);
            else
            {
                symbol += Base.kNumMidLenSymbols;
                symbol += m_HighCoder.Decode(rangeDecoder);
            }
            return symbol;
        }
    }
}
